import 'package:flutter/material.dart';

class AnchoredOverlay extends StatelessWidget {
  final bool showOverlay;
  final Widget Function(BuildContext, Offset anchor) overlayBuilder;
  final Widget child;

  AnchoredOverlay({
    this.showOverlay,
    this.overlayBuilder,
    this.child,
  });

  @override
  build(context) => Container(
        child: LayoutBuilder(
            builder: (context, constraints) => OverlayBuilder(
                  showOverlay: showOverlay,
                  overlayBuilder: (BuildContext overlayContext) {
                    RenderBox box = context.findRenderObject() as RenderBox;
                    return overlayBuilder(
                        overlayContext,
                        box.size
                            .center(box.localToGlobal(const Offset(0.0, 0.0))));
                  },
                  child: child,
                )),
      );
}

class OverlayBuilder extends StatefulWidget {
  final bool showOverlay;
  final Function(BuildContext) overlayBuilder;
  final Widget child;

  OverlayBuilder({
    this.showOverlay = false,
    this.overlayBuilder,
    this.child,
  });

  @override
   createState() => _OverlayBuilderState();
}

class _OverlayBuilderState extends State<OverlayBuilder> {
  OverlayEntry overlayEntry;

  @override
  initState() {
    super.initState();
    if (widget.showOverlay) {
      WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay());
    }
  }

  @override
  didUpdateWidget(OverlayBuilder oldWidget) {
    super.didUpdateWidget(oldWidget);
    WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
  }

  @override
  reassemble() {
    super.reassemble();
    WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
  }

  @override
  dispose() {
    if (isShowingOverlay()) {
      hideOverlay();
    }
    super.dispose();
  }

  bool isShowingOverlay() => overlayEntry != null;
  showOverlay() {
    overlayEntry = OverlayEntry(builder: widget.overlayBuilder);
    addToOverlay(overlayEntry);
  }

  addToOverlay(OverlayEntry entry) async {
    Overlay.of(context).insert(entry);
  }

  hideOverlay() {
    overlayEntry.remove();
    overlayEntry = null;
  }

  syncWidgetAndOverlay() {
    if (isShowingOverlay() && !widget.showOverlay) {
      hideOverlay();
    } else if (!isShowingOverlay() && widget.showOverlay) {
      showOverlay();
    }
  }
  @override
  build(context) => widget.child;
}

class CenterAbout extends StatelessWidget {
  final Offset position;
  final Widget child;
  CenterAbout({
    this.position,
    this.child,
  });

  @override
  build(context) => Positioned(
        top: position.dy,
        left: position.dx,
        child: FractionalTranslation(
            translation: const Offset(-0.5, -0.5), child: child),
      );
}
